using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;


namespace XNASubdivision
{
    public class DXTriangleMesh
    {
        VertexDeclaration m_vertexDeclaration;
        VertexBuffer m_vertexBuffer;
        IndexBuffer m_indexBuffer;
        int m_vertexCount;
        int m_faceCount;
        PrimitiveType m_primitiveType;

        public DXTriangleMesh()
        {
        }

        public DXTriangleMesh(GraphicsDevice p_device, QuadMesh p_quadMesh)
        {

            m_vertexDeclaration = new VertexDeclaration(p_device, VertexPositionNormalTexture.VertexElements);
            m_primitiveType = PrimitiveType.TriangleList;

            m_vertexCount = p_quadMesh.VertexCount;
            m_faceCount = p_quadMesh.QuadCount * 2;

            VertexPositionNormalTexture[] vertices = new VertexPositionNormalTexture[m_vertexCount];
            for (int i = 0; i < m_vertexCount; i++)
            {
                vertices[i] = new VertexPositionNormalTexture(p_quadMesh.Vertices[i], p_quadMesh.Normals[i], p_quadMesh.TextureUVs[i]);   // TODO: this is WRONG
            }

            m_vertexBuffer = new VertexBuffer(p_device, VertexPositionNormalTexture.SizeInBytes * vertices.Length, ResourceUsage.WriteOnly, ResourceManagementMode.Automatic);
            m_vertexBuffer.SetData<VertexPositionNormalTexture>(vertices);


            m_indexBuffer = new IndexBuffer(p_device, typeof(uint), m_faceCount * 3, ResourceUsage.WriteOnly, ResourceManagementMode.Automatic);
            int iIndices = 0;
            uint[] indices = new uint[m_faceCount * 3];
            for (int i = 0; i < p_quadMesh.QuadCount; i++)
            {
                // triangle 1
                indices[iIndices++] = (uint)p_quadMesh.Quads[i].vertInd0;
                indices[iIndices++] = (uint)p_quadMesh.Quads[i].vertInd1;
                indices[iIndices++] = (uint)p_quadMesh.Quads[i].vertInd2;

         
                // triangle 2
                indices[iIndices++] = (uint)p_quadMesh.Quads[i].vertInd0;
                indices[iIndices++] = (uint)p_quadMesh.Quads[i].vertInd2;
                indices[iIndices++] = (uint)p_quadMesh.Quads[i].vertInd3;
            }

            m_indexBuffer.SetData<uint>(indices);

         }

        public DXTriangleMesh(GraphicsDevice p_device, VertexPositionNormalTexture[] p_vertices, uint[] p_indices)
        {
            m_vertexDeclaration = new VertexDeclaration(p_device, VertexPositionNormalTexture.VertexElements);
            m_primitiveType = PrimitiveType.TriangleList;
            m_vertexCount = p_vertices.Length;
            m_faceCount = p_indices.Length / 3;

            m_vertexBuffer = new VertexBuffer(p_device, VertexPositionNormalTexture.SizeInBytes * p_vertices.Length, ResourceUsage.WriteOnly, ResourceManagementMode.Automatic);
            m_vertexBuffer.SetData<VertexPositionNormalTexture>(p_vertices);


            m_indexBuffer = new IndexBuffer(p_device, typeof(uint), p_indices.Length, ResourceUsage.WriteOnly, ResourceManagementMode.Automatic);
            m_indexBuffer.SetData<uint>(p_indices);
        }

          
        public VertexBuffer VertexBuffer
        {
            get { return m_vertexBuffer; }
            set { m_vertexBuffer = value; }
        }

        public IndexBuffer IndexBuffer
        {
            get { return m_indexBuffer; }
            set { m_indexBuffer = value; }
        }

        public VertexDeclaration VertexDeclaration
        {
            get { return m_vertexDeclaration; }
            set { m_vertexDeclaration = value; }
        }

        public int VertexCount
        {
            get { return m_vertexCount; }
            set { m_vertexCount = value; }
        }

        public int FaceCount
        {
            get { return m_faceCount; }
            set { m_faceCount = value; }
        }

        public PrimitiveType PrimitiveType
        {
            get { return m_primitiveType; }
            set { m_primitiveType = value; }
        }
     

        private void CalculateNormals()
        {
            //for (int i = 0; i < _indexCount; i += 3)
            //{
            //    Vector3 vert0 = _vertices[_indices[i]].Position;
            //    Vector3 vert1 = _vertices[_indices[i + 1]].Position;
            //    Vector3 vert2 = _vertices[_indices[i + 2]].Position;

            //    Vector3 normal = Vector3.Normalize(Vector3.Cross(vert2 - vert0, vert1 - vert0));

            //    _vertices[_indices[i]].Normal += normal;
            //    _vertices[_indices[i + 1]].Normal += normal;
            //    _vertices[_indices[i + 2]].Normal += normal;
            //}

            //for (int vert = 0; vert < _vertexCount; vert++)
            //    _vertices[vert].Normal.Normalize();
        }


        public static DXTriangleMesh CreateDemoRect(GraphicsDevice p_device)
        {
            DXTriangleMesh geometryMesh = new DXTriangleMesh();
            geometryMesh.m_vertexDeclaration = new VertexDeclaration(p_device, VertexPositionNormalTexture.VertexElements);

            geometryMesh.m_primitiveType = PrimitiveType.TriangleList;
            geometryMesh.m_vertexCount = 6;
            geometryMesh.m_faceCount = 2;

            VertexPositionNormalTexture[] demoRectVertices = new VertexPositionNormalTexture[geometryMesh.m_vertexCount];

            Vector3 bottomLeftFront = new Vector3(-1.0f, 0.0f, 1.0f);
            Vector3 bottomLeftBack = new Vector3(-1.0f, 0.0f, -1.0f);
            Vector3 bottomRightBack = new Vector3(1.0f, 0.0f, -1.0f);
            Vector3 bottomRightFront = new Vector3(1.0f, 0.0f, 1.0f);

            Vector2 textureTopLeft = new Vector2(0.0f, 0.0f);
            Vector2 textureTopRight = new Vector2(1.0f, 0.0f);
            Vector2 textureBottomLeft = new Vector2(0.0f, 1.0f);
            Vector2 textureBottomRight = new Vector2(1.0f, 1.0f);

            Vector3 bottomNormal = new Vector3(0.0f, -1.0f, 0.0f);

            demoRectVertices[0] = new VertexPositionNormalTexture(bottomLeftFront, bottomNormal, textureTopLeft);
            demoRectVertices[1] = new VertexPositionNormalTexture(bottomLeftBack, bottomNormal, textureBottomLeft);
            demoRectVertices[2] = new VertexPositionNormalTexture(bottomRightBack, bottomNormal, textureBottomRight);
            demoRectVertices[3] = new VertexPositionNormalTexture(bottomLeftFront, bottomNormal, textureTopLeft);
            demoRectVertices[4] = new VertexPositionNormalTexture(bottomRightBack, bottomNormal, textureBottomRight);
            demoRectVertices[5] = new VertexPositionNormalTexture(bottomRightFront, bottomNormal, textureTopRight);

            geometryMesh.m_vertexBuffer = new VertexBuffer(p_device,
                VertexPositionNormalTexture.SizeInBytes * demoRectVertices.Length,
                ResourceUsage.None, ResourceManagementMode.Automatic);

            geometryMesh.m_vertexBuffer.SetData<VertexPositionNormalTexture>(demoRectVertices);

            // Index buffer
            geometryMesh.m_indexBuffer = new IndexBuffer(p_device, typeof(ushort), 2 * 3, ResourceUsage.WriteOnly, ResourceManagementMode.Automatic);
            geometryMesh.m_indexBuffer.SetData<ushort>(new ushort[] { 0, 1, 2, 3, 4, 5 });

            return geometryMesh;
        }
    }
}
